home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Applications / NIH Image 1.62b11 / src / Math.p < prev    next >
Text File  |  1996-03-01  |  41KB  |  1,564 lines

  1. unit Math;
  2.  
  3. interface
  4.  
  5.     uses
  6.         Types, Memory, QuickDraw, QuickDrawText, Packages, Menus, Events, Fonts, 
  7.         Scrap, ToolUtils, Resources, Errors, Palettes, StandardFile, Windows,
  8.         Controls, TextEdit, Files, Dialogs, TextUtils, Finder, MixedMode, Processes,
  9.         globals, Utilities, RealUtils, Graphics, Camera, Filters, Lut, fft;
  10.  
  11.  
  12.     procedure SetPasteMode (item: integer);
  13.     procedure DoMouseDownInPasteControl (loc: point);
  14.     procedure ShowPasteControl;
  15.     procedure DrawPasteControl;
  16.     procedure DoArithmetic (MenuItem: integer; constant: extended);
  17.     function GetMathRoi(Src1PicNum, Src2PicNum:integer; var roi:rect):boolean;
  18.     procedure DoMath (Src1PicNum, Src2PicNum: integer; DstInfo:InfoPtr; roi:rect);
  19.     procedure DoPasteMath;
  20.     procedure DoImageMath;
  21.     function GetInfoPtr (PicN: integer): InfoPtr;
  22.  
  23.  
  24. implementation
  25.  
  26.     const
  27.         Src1Item = 7;
  28.         Src2Item = 8;
  29.         OpItem = 9;
  30.  
  31.  
  32.     procedure DoPasteMath;
  33.         const
  34.             PixelsPerUpdate = 15000;
  35.         var
  36.             nrows, ncols, hSrcStart, vSrcStart, hDstStart, vDstStart: integer;
  37.             SaveInfo: InfoPtr;
  38.             h, v, vDst, PixelCount, offset: integer;
  39.             Src, Dst: LineType;
  40.             tmp, range, min, max, StartTicks: LongInt;
  41.             x, xmax, xmin, xrange, xxscale: extended;
  42.     begin
  43.         if TooWide then
  44.             exit(DoPasteMath);
  45.         ShowWatch;
  46.         OpPending := false;
  47.         WhatToUndo := UndoPaste;
  48.         KillRoi;
  49.         with info^.RoiRect do begin
  50.                 ncols := right - left;
  51.                 nrows := bottom - top;
  52.                 hDstStart := left;
  53.                 vDstStart := top;
  54.             end;
  55.         with ClipBufInfo^.RoiRect do begin
  56.                 hSrcStart := left;
  57.                 vSrcStart := top;
  58.             end;
  59.         if hDstStart < 0 then begin
  60.                 offset := -hDstStart;
  61.                 hDstStart := 0;
  62.                 hSrcStart := hSrcStart + offset;
  63.                 ncols := ncols - offset;
  64.             end;
  65.         if vDstStart < 0 then begin
  66.                 offset := -vDstStart;
  67.                 vDstStart := 0;
  68.                 vSrcStart := vSrcStart + offset;
  69.                 nrows := nrows - offset;
  70.             end;
  71.         with info^.PicRect do begin
  72.                 if hDstStart + ncols > right then
  73.                     ncols := right - hDstStart;
  74.                 if vDstStart + nrows > bottom then
  75.                     nrows := bottom - vDstStart;
  76.             end;
  77.         SaveInfo := info;
  78.         vDst := vDstStart;
  79.         min := 999999;
  80.         max := -999999;
  81.         xmin := 999999.0;
  82.         xmax := -999999.0;
  83.         StartTicks := TickCount;
  84.        {First pass to find result range}
  85.         if ScaleArithmetic then begin
  86.                 for v := vSrcStart to vSrcStart + nRows - 1 do begin
  87.                         Info := ClipBufInfo;
  88.                         GetLine(hSrcStart, v, nCols, Src);
  89.                         Info := SaveInfo;
  90.                         GetLine(hDstStart, vDst, nCols, Dst);
  91.                         case CurrentOp of
  92.                             AddOp:  begin
  93.                                     for h := 0 to nCols - 1 do begin
  94.                                             tmp := Src[h] + Dst[h];
  95.                                             if tmp > max then
  96.                                                 max := tmp;
  97.                                             if tmp < Min then
  98.                                                 min := tmp;
  99.                                         end;
  100.                                 end;
  101.                             SubtractOp:  begin
  102.                                     for h := 0 to nCols - 1 do begin
  103.                                             tmp := Dst[h] - Src[h];
  104.                                             if tmp > max then
  105.                                                 max := tmp;
  106.                                             if tmp < Min then
  107.                                                 min := tmp;
  108.                                         end;
  109.                                 end;
  110.                             MultiplyOp:  begin
  111.                                     for h := 0 to nCols - 1 do begin
  112.                                             tmp := Dst[h];
  113.                                             tmp := tmp * Src[h];
  114.                                             if tmp > max then
  115.                                                 max := tmp;
  116.                                             if tmp < min then
  117.                                                 min := tmp;
  118.                                         end;
  119.                                 end;
  120.                             DivideOp:  begin
  121.                                     for h := 0 to nCols - 1 do begin
  122.                                             tmp := Src[h];
  123.                                             if tmp = 0 then
  124.                                                 tmp := 1;
  125.                                             x := Dst[h] / tmp;
  126.                                             if x > xmax then begin
  127.                                                     xmax := x;
  128.                                                 end;
  129.                                             if x < xmin then
  130.                                                 xmin := x;
  131.                                         end;
  132.                                 end;
  133.                         end;
  134.                         vDst := vDst + 1;
  135.                     end;
  136.                 vDst := vDstStart;
  137.                 if CurrentOp = DivideOp then begin
  138.                         xrange := xmax - xmin;
  139.                         if xrange <> 0.0 then
  140.                             xxscale := 256.0 / xrange
  141.                         else
  142.                             xxscale := 1;
  143.                     end
  144.                 else
  145.                     range := max - min;
  146.             end; {if ScaleArithmetic=true}
  147.         PixelCount := 0;
  148.        {Second pass to do arithmetic and scaling}
  149.         for v := vSrcStart to vSrcStart + nRows - 1 do begin
  150.                 Info := ClipBufInfo;
  151.                 GetLine(hSrcStart, v, nCols, Src);
  152.                 Info := SaveInfo;
  153.                 GetLine(hDstStart, vDst, nCols, Dst);
  154.                 case CurrentOp of
  155.                     AddOp: 
  156.                         if ScaleArithmetic then
  157.                             for h := 0 to nCols - 1 do begin
  158.                                     tmp := Dst[h] + Src[h] - min;
  159.                                     if range <> 0 then
  160.                                         tmp := tmp * 256 div range
  161.                                     else
  162.                                         tmp := BackgroundIndex;
  163.                                     if tmp > 255 then
  164.                                         dst[h] := 255
  165.                                     else
  166.                                         dst[h] := tmp;
  167.                                 end
  168.                         else
  169.                             for h := 0 to nCols - 1 do begin
  170.                                     tmp := Dst[h] + Src[h];
  171.                                     if tmp > 255 then
  172.                                         dst[h] := 255
  173.                                     else
  174.                                         dst[h] := tmp;
  175.                                 end;
  176.                     SubtractOp: 
  177.                         if ScaleArithmetic then
  178.                             for h := 0 to nCols - 1 do begin
  179.                                     tmp := Dst[h] - Src[h] - min;
  180.                                     if range <> 0 then
  181.                                         tmp := tmp * 256 div range
  182.                                     else
  183.                                         tmp := BackgroundIndex;
  184.                                     if tmp > 255 then
  185.                                         dst[h] := 255
  186.                                     else
  187.                                         dst[h] := tmp;
  188.                                 end
  189.                         else
  190.                             for h := 0 to nCols - 1 do begin
  191.                                     tmp := Dst[h] - Src[h];
  192.                                     if tmp < 0 then
  193.                                         dst[h] := 0
  194.                                     else
  195.                                         dst[h] := tmp;
  196.                                 end;
  197.                     MultiplyOp: 
  198.                         if ScaleArithmetic then
  199.                             for h := 0 to nCols - 1 do begin
  200.                                     tmp := Dst[h];
  201.                                     tmp := tmp * Src[h] - min;
  202.                                     if range <> 0 then
  203.                                         tmp := tmp * 256 div range
  204.                                     else
  205.                                         tmp := BackgroundIndex;
  206.                                     if tmp > 255 then
  207.                                         dst[h] := 255
  208.                                     else
  209.                                         dst[h] := tmp;
  210.                                 end
  211.                         else
  212.                             for h := 0 to nCols - 1 do begin
  213.                                     tmp := Dst[h];
  214.                                     tmp := tmp * Src[h];
  215.                                     if tmp > 255 then
  216.                                         dst[h] := 255
  217.                                     else
  218.                                         dst[h] := tmp;
  219.                                 end;
  220.                     DivideOp: 
  221.                         if ScaleArithmetic then
  222.                             for h := 0 to nCols - 1 do begin
  223.                                     tmp := Src[h];
  224.                                     if tmp = 0 then
  225.                                         tmp := 1;
  226.                                     x := Dst[h] / tmp - xmin;
  227.                                     if xrange <> 0.0 then
  228.                                         tmp := trunc(x * xxscale)
  229.                                     else
  230.                                         tmp := BackgroundIndex;
  231.                                     if tmp > 255 then
  232.                                         tmp := 255;
  233.                                     if tmp < 0 then
  234.                                         tmp := 0;
  235.                                     dst[h] := tmp;
  236.                                 end
  237.                         else
  238.                             for h := 0 to nCols - 1 do begin
  239.                                     tmp := Src[h];
  240.                                     if tmp = 0 then
  241.                                         tmp := 1;
  242.                                     dst[h] := Dst[h] div tmp;
  243.                                 end;
  244.                 end;
  245.                 PutLine(hDstStart, vDst, nCols, Dst);
  246.                 vDst := vDst + 1;
  247.                 PixelCount := PixelCount + ncols;
  248.                 if PixelCount > PixelsPerUpdate then begin
  249.                         UpdateScreen(info^.RoiRect);
  250.                         if CommandPeriod then begin
  251.                                 UpdateScreen(info^.RoiRect);
  252.                                 beep;
  253.                                 exit(DoPasteMath)
  254.                             end;
  255.                         PixelCount := 0;
  256.                     end;
  257.             end;
  258.         with info^ do begin
  259.                 ShowTime(StartTicks, RoiRect, '');
  260.                 UpdateScreen(RoiRect);
  261.             end;
  262.     end;
  263.  
  264.  
  265.     procedure SetPasteMode (item: integer);
  266.         var
  267.             SavePort: GrafPtr;
  268.             BlendColor: rgbColor;
  269.     begin
  270.         if not macro then begin
  271.                 SetForegroundColor(BlackIndex);
  272.                 SetBackGroundColor(WhiteIndex);
  273.             end;
  274.         case Item of
  275.             CopyModeItem: 
  276.                 PasteTransferMode := SrcCopy;
  277.             AndItem: 
  278.                 PasteTransferMode := NotSrcBic; {And}
  279.             OrItem: 
  280.                 PasteTransferMode := SrcOr;
  281.             XorItem: 
  282.                 PasteTransferMode := SrcXor;
  283.             ReplaceItem: 
  284.                 PasteTransferMode := Transparent;
  285.             BlendItem:  begin
  286.                     GetPort(SavePort);
  287.                     with BlendColor do begin
  288.                             red := 32767;
  289.                             blue := 32767;
  290.                             green := 32767;
  291.                         end;
  292.                     SetPort(GrafPtr(info^.osPort));
  293.                     OpColor(BlendColor);
  294.                     SetPort(SavePort);
  295.                     PasteTransferMode := Blend;
  296.                 end;
  297.             otherwise
  298.         end; {case}
  299.     end;
  300.  
  301.  
  302.     function GetTransferModeItem: integer;
  303.     begin
  304.         case PasteTransferMode of
  305.             SrcCopy: 
  306.                 GetTransferModeItem := CopyModeItem;
  307.             NotSrcBic: 
  308.                 GetTransferModeItem := AndItem;
  309.             SrcOr: 
  310.                 GetTransferModeItem := OrItem;
  311.             SrcXor: 
  312.                 GetTransferModeItem := XorItem;
  313.             Transparent: 
  314.                 GetTransferModeItem := ReplaceItem;
  315.             Blend: 
  316.                 GetTransferModeItem := BlendItem;
  317.         end;
  318.     end;
  319.  
  320.  
  321.     procedure DrawPasteControl;
  322.         const
  323.             bWidth = 64;
  324.             bHeight = 14;
  325.             vinc = 18;
  326.             bhloc = 114;
  327.             bvloc = 6;
  328.         var
  329.             tPort: GrafPtr;
  330.             i, hloc, vloc, item: integer;
  331.             tType: pcItemType;
  332.             tRect, TriangleRect: rect;
  333.             ItemStr: str255;
  334.     begin
  335.         GetPort(tPort);
  336.         SetPort(PasteControl);
  337.         with PcItem[1] do begin
  338.                 SetRect(r, 15, 22, 95, 40);
  339.                 itype := pcPopupMenu;
  340.                 str := 'Transfer Mode';
  341.             end;
  342.         with pcItem[2] do begin
  343.                 SetRect(r, 88, 50, 100, 62);
  344.                 itype := pcCheckBox;
  345.                 str := 'Scale Math';
  346.             end;
  347.         with pcItem[3] do begin
  348.                 SetRect(r, 88, 65, 100, 77);
  349.                 itype := pcCheckBox;
  350.                 str := 'Live Paste';
  351.             end;
  352.         hloc := bhloc;
  353.         vloc := bvloc;
  354.         tType := pcButton;
  355.         with pcItem[4] do begin
  356.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  357.                 itype := tType;
  358.                 str := 'Add';
  359.             end;
  360.         vloc := vloc + vinc;
  361.         with pcItem[5] do begin
  362.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  363.                 itype := tType;
  364.                 str := 'Subtract';
  365.             end;
  366.         vloc := vloc + vinc;
  367.         with pcItem[6] do begin
  368.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  369.                 itype := tType;
  370.                 str := 'Multiply';
  371.             end;
  372.         vloc := vloc + vinc;
  373.         with pcItem[7] do begin
  374.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  375.                 itype := tType;
  376.                 str := 'Divide';
  377.             end;
  378.         TextFont(SystemFont);
  379.         TextSize(12);
  380.         for i := 1 to npcItems do
  381.             with pcItem[i] do
  382.                 case iType of
  383.                     pcPopupMenu: 
  384.                         with r do begin
  385.                                 MoveTo(r.left - 10, r.top - 4);
  386.                                 DrawString(str);
  387.                                 DrawDropBox(r);
  388.                                 item := GetTransferModeItem;
  389.                                 GetMenuItemText(TransferModeMenuH, item, ItemStr);
  390.                                 MoveTo(left + 13, bottom - 5);
  391.                                 DrawString(ItemStr);
  392.                             end;
  393.                     pcCheckBox: 
  394.                         with r do begin
  395.                                 MoveTo(left - StringWidth(str) - 4, bottom - 2);
  396.                                 DrawString(str);
  397.                                 EraseRect(r);
  398.                                 FrameRect(r);
  399.                                 if ((i = 2) and ScaleArithmetic) or ((i = 3) and LivePasteMode) then begin
  400.                                         MoveTo(left, top);
  401.                                         LineTo(right - 1, bottom - 1);
  402.                                         MoveTo(left, bottom - 1);
  403.                                         LineTo(right - 1, top);
  404.                                     end;
  405.                             end;
  406.                     pcButton:  begin
  407.                             FrameRoundRect(r, 6, 6);
  408.                             with r do
  409.                                 MoveTo(left + ((right - left) - StringWidth(str)) div 2, bottom - 3);
  410.                             DrawString(str);
  411.                         end;
  412.                 end; {case}
  413.         SetPort(tPort);
  414.     end;
  415.  
  416.  
  417.     procedure DoMouseDownInPasteControl; {(loc:point)}
  418.         var
  419.             nItem, i, MenuItem: integer;
  420.             tr: rect;
  421.     begin
  422.         if not (OpPending and (CurrentOp = PasteOp)) then begin
  423.                 PutError('Paste Control is only available during paste operations.');
  424.                 exit(DoMouseDownInPasteControl);
  425.             end;
  426.         SetPort(PasteControl);
  427.         GlobalToLocal(loc);
  428.         nItem := 0;
  429.         for i := 1 to npcItems do
  430.             if PtInRect(loc, pcItem[i].r) then
  431.                 nitem := i;
  432.         if nItem > 0 then begin
  433.                 case pcItem[nItem].itype of
  434.                     pcPopUpMenu: 
  435.                         with pcItem[1].r do begin
  436.                                 MenuItem := PopUpMenu(TransferModeMenuH, left, top, GetTransferModeItem);
  437.                                 SetPasteMode(MenuItem);
  438.                             end;
  439.                     pcCheckBox:  begin
  440.                             tr := pcItem[nItem].r;
  441.                             InsetRect(tr, 1, 1);
  442.                             FrameRect(tr);
  443.                             if nitem = 2 then
  444.                                 ScaleArithmetic := not ScaleArithmetic;
  445.                             if nitem = 3 then begin
  446.                                     LivePasteMode := not LivePasteMode;
  447.                                     if LivePasteMode then begin
  448.                                             ExternalTrigger := false;
  449.                                             UpdateVideoControl
  450.                                         end;
  451.                                 end;
  452.                         end;
  453.                     pcButton:  begin
  454.                             InvertRoundRect(pcItem[nitem].r, 6, 6);
  455.                             while Button and (nitem > 0) do begin
  456.                                     GetMouse(loc);
  457.                                     if not PtInRect(loc, pcItem[nitem].r) then begin
  458.                                             InvertRoundRect(pcItem[nitem].r, 6, 6);
  459.                                             nItem := 0;
  460.                                         end;
  461.                                 end;
  462.                         end;
  463.                 end; {case}
  464.                 repeat
  465.                 until not button;
  466.                 if nItem > 0 then
  467.                     with pcItem[nitem] do begin
  468.                             case itype of
  469.                                 pcPopupMenu: 
  470.                                     ;
  471.                                 pcCheckBox:  begin
  472.                                     end;
  473.                                 pcButton:  begin
  474.                                         InvertRoundRect(pcItem[nitem].r, 6, 6);
  475.                                         if info^.RoiType = RectRoi then begin
  476.                                                 case nitem of
  477.                                                     4: 
  478.                                                         CurrentOp := AddOp;
  479.                                                     5: 
  480.                                                         CurrentOp := SubtractOp;
  481.                                                     6: 
  482.                                                         CurrentOp := MultiplyOp;
  483.                                                     7: 
  484.                                                         CurrentOp := DivideOp;
  485.                                                 end;
  486.                                                 DoPasteMath;
  487.                                             end; {if}
  488.                                     end; {pcButton}
  489.                             end; {case}
  490.                         end; {with}
  491.             end; {if nitem>0}
  492.         if LivePasteMode and (((WhatsOnClip <> CameraPic) and (WhatsOnClip <> LivePic)) or (FrameGrabber =NoFrameGrabber)) then begin
  493.                 PutError('"Live Paste" requires that a rectangular selection be first copied from the Camera window to the Clipboard.');
  494.                 LivePasteMode := false;
  495.             end;
  496.         if LivePasteMode and (info^.PictureType = FrameGrabberType) then begin
  497.                 PutError('Live pasting into the Camera window is not supported.');
  498.                 LivePasteMode := false;
  499.             end;
  500.         DrawPasteControl;
  501.     end;
  502.  
  503.  
  504.     procedure ShowPasteControl;
  505.         var
  506.             tPort: GrafPtr;
  507.             trect: rect;
  508.             wp: ^WindowPtr;
  509.     begin
  510.         SetRect(trect, PasteControlLeft, PasteControlTop, PasteControlLeft + pcwidth, PasteControlTop + pcheight);
  511.         PasteControl := NewWindow(nil, trect, 'Paste Control', true, rDocProc, nil, true, 0);
  512.         WindowPeek(PasteControl)^.WindowKind := PasteControlKind;
  513.         wp := pointer(GhostWindow);
  514.         wp^ := PasteControl;
  515.         PasteTransferMode := SrcCopy;
  516.         LivePasteMode := false;
  517.     end;
  518.  
  519.  
  520.     function GetRealC (message: str255; default: extended; precision: integer; var Canceled: boolean): extended;
  521.         const
  522.             NumberID = 3;
  523.             CalibrateID = 5;
  524.         var
  525.             mylog: DialogPtr;
  526.             item: integer;
  527.     begin
  528.         InitCursor;
  529.         ParamText(message, '', '', '');
  530.         mylog := GetNewDialog(290, nil, pointer(-1));
  531.         SetDReal(MyLog, NumberID, default, precision);
  532.         SetDlogItem(MyLog, CalibrateID, ord(RealArithmetic));
  533.         SelectdialogItemText(MyLog, NumberID, 0, 32767);
  534.         OutlineButton(MyLog, ok, 16);
  535.         repeat
  536.             ModalDialog(nil, item);
  537.             if item = CalibrateID then begin
  538.                 RealArithmetic := not RealArithmetic;
  539.                 SetDlogItem(MyLog, CalibrateID, ord(RealArithmetic));
  540.             end;
  541.         until (item = ok) or (item = cancel);
  542.         if item = ok then begin
  543.                 GetRealC := GetDReal(MyLog, NumberID);
  544.                 Canceled := false;
  545.             end
  546.         else begin
  547.                 GetRealC := default;
  548.                 Canceled := true;
  549.             end;
  550.         DisposeDialog(mylog);
  551.     end;
  552.  
  553.  
  554.     procedure DoArithmetic (MenuItem: integer; constant: extended);
  555.         var
  556.             table: LookupTable;
  557.             i, iConst, pNum, digits: integer;
  558.             tmp: LongInt;
  559.             LogScale: extended;
  560.             Canceled: boolean;
  561.             result: str255;
  562.     begin
  563.         canceled := false;
  564.         if info^.fit <> Uncalibrated then
  565.             RealArithmetic := true;
  566.         if not macro then
  567.             case menuItem of
  568.                 AddItem: 
  569.                     constant := GetRealC('Constant to add:', 25, 0, Canceled);
  570.                 SubtractItem: 
  571.                     constant := GetRealC('Constant to subtract:', 25, 0, Canceled);
  572.                 MultiplyItem:  begin
  573.                         constant := GetRealC('Constant to multiply by:', 1.25, 2, Canceled);
  574.                         if constant < 0.0 then begin
  575.                                 PutError('Constant must be positive.');
  576.                                 exit(DoArithmetic);
  577.                             end;
  578.                     end;
  579.                 DivideItem:  begin
  580.                         constant := GetRealC('Constant to divide by:', 1.25, 2, Canceled);
  581.                         if constant <= 0.0 then begin
  582.                                 PutError('Constant must be nonzero and positive.');
  583.                                 exit(DoArithmetic);
  584.                             end;
  585.                     end;
  586.                 AndItem2: 
  587.                     constant := GetInt('AND image with:', 240, Canceled);
  588.                 OrItem2: 
  589.                     constant := GetInt('OR image with:', 31, Canceled);
  590.                 XorItem2: 
  591.                     constant := GetInt('XOR image with:', 31, Canceled);
  592.                 LogItem:  begin
  593.                         if not CheckCalibration then
  594.                             exit(DoArithmetic);
  595.                         constant := 0.0;
  596.                         LogScale := 255.0 / ln(255.0);
  597.                     end;
  598.             end; {case}
  599.         if Canceled then
  600.             exit(DoArithmetic);
  601.         if RealArithmetic and (MenuItem >= AddItem) and (MenuItem <= DivideItem)  and not macro then begin
  602.             if constant < 1.0 then
  603.                 digits := 3
  604.             else if constant <10.0 then
  605.                 digits := 2
  606.             else digits := 1;
  607.             if trunc(constant) = constant then
  608.                 digits := 0;
  609.             with info^ do case MenuItem of
  610.                 AddItem: begin
  611.                         MathGain := 1.0;
  612.                         MathOffset := constant;
  613.                         result := StringOf(title, '+', constant:1:digits) 
  614.                     end;
  615.                 SubtractItem: begin
  616.                         MathGain := 1.0;
  617.                         MathOffset := -constant;
  618.                         result := StringOf(title, '-', constant:1:digits) 
  619.                     end;
  620.                 MultiplyItem: begin
  621.                         MathGain := constant;
  622.                         MathOffset := 0.0;
  623.                         result := StringOf(title, '*', constant:1:digits) 
  624.                     end;
  625.                 DivideItem: begin
  626.                         MathGain := 1.0 / constant;
  627.                         MathOffset := 0.0;
  628.                         result := StringOf(title, '/', constant:1:digits) 
  629.                     end;
  630.             end;
  631.             pNum := info^.picNum;
  632.             with info^.PicRect do
  633.                 if not NewRealWindow(result, right-left, bottom-top) then
  634.                 exit(DoArithmetic);
  635.             CurrentMathOp := CopyMath;
  636.             RealImageMath := true;
  637.             DoMath(pNum, pNum, Info, info^.picRect);
  638.             exit(DoArithmetic);
  639.         end;
  640.         iconst := trunc(constant);
  641.         for i := 0 to 255 do begin
  642.                 case MenuItem of
  643.                     AddItem: 
  644.                         tmp := round(i + constant);
  645.                     SubtractItem: 
  646.                         tmp := round(i - constant);
  647.                     MultiplyItem: 
  648.                         tmp := round(i * constant);
  649.                     DivideItem: 
  650.                         tmp := round(i / constant);
  651.                     AndItem2: 
  652.                         tmp := band(i, iconst);
  653.                     OrItem2: 
  654.                         tmp := bor(i, iconst);
  655.                     XorItem2:
  656.                         tmp := bxor(i, iconst);
  657.                     LogItem:
  658.                         if i = 0 then
  659.                             tmp := 0
  660.                         else
  661.                             tmp := round(ln(i) * LogScale);
  662.                 end;
  663.                 if tmp < 0 then
  664.                     tmp := 0;
  665.                 if tmp > 255 then
  666.                     tmp := 255;
  667.                 table[i] := tmp;
  668.             end;
  669.         ApplyTable(table);
  670.         if (MenuItem >= AddItem) and (MenuItem <= DivideItem) then
  671.             RemoveDensityCalibration;
  672.     end;
  673.  
  674.  
  675.     function GetInfoPtr (PicN: integer): InfoPtr;
  676.   {Converts a pic number or pid number to an Info ptr.}
  677.         var
  678.             i: integer;
  679.     begin
  680.         i := 0;
  681.         while (PicN < 0) and (i < nPics) do begin
  682.                 i := i + 1;
  683.                 if InfoPtr(WindowPeek(PicWindow[i])^.RefCon)^.pidNum = PicN then
  684.                     PicN := i;
  685.             end;
  686.         if (PicN >= 1) and (PicN <= nPics) then
  687.             GetInfoPtr := pointer(WindowPeek(PicWindow[PicN])^.RefCon)
  688.         else
  689.             GetInfoPtr := nil;
  690.     end;
  691.  
  692.  
  693.     procedure ShowRoi(roi:rect);
  694.     begin
  695.         with roi do ShowMessage(StringOf(left:4, top:4, right-left:4, bottom-top:4));
  696.         wait(200);
  697.     end;
  698.  
  699.  
  700.     function GetMathRoi(Src1PicNum, Src2PicNum:integer; var roi:rect):boolean;
  701.         var
  702.             Src1Info, Src2Info: InfoPtr;
  703.             ignore:boolean;
  704.     begin
  705.         KillRoi;
  706.         GetMathRoi:=false;
  707.         Src1Info := GetInfoPtr(Src1PicNum);
  708.         Src2Info := GetInfoPtr(Src2PicNum);
  709.          if (Src1Info = nil) or (Src2Info = nil) then begin
  710.                 PutError('Bad pic num or pid num.');
  711.                 AbortMacro;
  712.                 exit(GetMathRoi);
  713.             end;
  714.         roi := Src1Info^.PicRect;
  715.         ignore := SectRect(roi, Src2Info^.PicRect, roi);
  716.         GetMathRoi:=true;
  717.     end;
  718.     
  719.     
  720.  
  721.     procedure DoFFTMath (Src1Info, Src2Info, DstInfo:InfoPtr);
  722.     {Does image math when both source images are FFTs.}
  723.     var
  724.         i, StartTicks: LongInt;
  725.         r, c, modAdd, rowMod, colMod, maxN: LongInt;
  726.         H2e, H2o, mag: real;
  727.         h1, h2, Out: rImagePtr;
  728.         roi:rect;
  729.     begin
  730.         maxN := Src1Info^.pixelsPerLine;
  731.         h1 :=  rImagePtr(Src1Info^.DataH^);
  732.         h2 :=  rImagePtr(Src2Info^.DataH^);
  733.         out := rImagePtr(DstInfo^.DataH^);
  734.         StartTicks := TickCount;
  735.         case CurrentMathOp of
  736.             MulMath, cMulMath: {Point by point Hartley multiplication or conjugate multiplication}
  737.                 for r := 0 to maxN - 1 do begin
  738.                     rowMod := (maxN - r) mod maxN;
  739.                     for c := 0 to maxN - 1 do begin
  740.                         colMod := (maxN - c) mod maxN;
  741.                         H2e := (h2^[r * maxN + c] + h2^[rowMod * maxN + colMod]) / 2;
  742.                         H2o := (h2^[r * maxN + c] - h2^[rowMod * maxN + colMod]) / 2;
  743.                         if CurrentMathOp = cMulMath then
  744.                             Out^[r * maxN + c] := h1^[r * maxN + c] * H2e - h1^[rowMod * maxN + colMod] * H2o
  745.                         else
  746.                             Out^[r * maxN + c] := h1^[r * maxN + c] * H2e + h1^[rowMod * maxN + colMod] * H2o;
  747.                     end;
  748.                 end; {for}
  749.             DivMath:  {Point by point Hartley division}
  750.                 for r := 0 to maxN - 1 do begin
  751.                     rowMod := (maxN - r) mod maxN;
  752.                     for c := 0 to maxN - 1 do begin
  753.                         colMod := (maxN - c) mod maxN;
  754.                         mag := H2^[r * maxN + c] * H2^[r * maxN + c] + H2^[rowMod * maxN + colMod] * H2^[rowMod * maxN + colMod];
  755.                         if mag < 1e-20 then
  756.                             mag := 1e-20;
  757.                         H2e := (H2^[r * maxN + c] + H2^[rowMod * maxN + colMod]);
  758.                         H2o := (H2^[r * maxN + c] - H2^[rowMod * maxN + colMod]);
  759.                         Out^[r * maxN + c] := (H1^[r * maxN + c] * H2e - H1^[rowMod * maxN + colMod] * H2o) / mag;
  760.                     end;
  761.                 end; {for}
  762.         end; {case}
  763.         info := dstInfo;
  764.         DisplayPowerSpectrum(out);
  765.         SetFFTWindowName(false);
  766.         hunlock(src1Info^.dataH);
  767.         hunlock(src2Info^.dataH);        
  768.         hunlock(dstInfo^.dataH);
  769.         SetRect(roi, 0, 0, maxN, maxN);
  770.         ShowTime(StartTicks, roi, '');
  771.     end; {DoFFTMath}
  772.  
  773.     
  774.     
  775.     procedure DoRealRealMath (Src1Info, Src2Info, DstInfo:InfoPtr; roi:rect);
  776.     {Does image math when both source images are real.}
  777.         var
  778.             nrows, ncols, hStart, vStart: LongInt;
  779.             h, v, i: LongInt;
  780.             tmp, tmp1, tmp2, StartTicks: LongInt;
  781.             SaveRow:LongInt;
  782.             NextUpdate: LongInt;
  783.             MaskRect:rect;
  784.             min, max, x, scale, x1, x2: extended;
  785.             s1Data, s2Data, rData: rImagePtr;
  786.             base: LongInt;
  787.             isFFT: boolean;
  788.             saveInfo: InfoPtr;
  789.  
  790.     begin
  791.         with src1Info^ do begin
  792.             if DataH = nil then begin
  793.                 saveInfo := info;
  794.                 info := src1Info;
  795.                 if not ConvertToReal then begin
  796.                     info := saveInfo;
  797.                     exit(DoRealRealMath)
  798.                 end;
  799.             end;
  800.             hlock(DataH);
  801.             s1Data := rImagePtr(DataH^);
  802.             isFFT := pos('FFT', title) = 1;
  803.         end;
  804.         if (CurrentMathOp <> CopyMath) then
  805.             with src2Info^ do begin
  806.                 if DataH = nil then begin
  807.                     saveInfo := info;
  808.                     info := src2Info;
  809.                     if not ConvertToReal then begin
  810.                         info := saveInfo;
  811.                         hunlock(DataH);
  812.                         exit(DoRealRealMath)
  813.                     end;
  814.                 end;
  815.                 hlock(DataH);
  816.                 s2Data := rImagePtr(DataH^);
  817.                 isFFT := isFFT and (pos('FFT', title) = 1);
  818.             end;
  819.         with DstInfo^ do begin
  820.             hlock(DataH);
  821.             rData := rImagePtr(DataH^);
  822.             isFFT := isFFT and (pixelsPerLine = nlines) and isPowerOf2(pixelsPerLine);
  823.         end;
  824.         if isFFT and (src1Info^.PixelsPerLine = src2Info^.PixelsPerLine)
  825.             and (src1Info^.PixelsPerLine = src1Info^.nLines)
  826.             and (CurrentMathOp in [MulMath, cMulMath, DivMath]) then begin
  827.                 doFFTMath(Src1Info, Src2Info, DstInfo);
  828.                 exit(DoRealRealMath);
  829.             end;
  830.         with roi do begin
  831.                 ncols := right - left;
  832.                 nrows := bottom - top;
  833.                 hStart := left;
  834.                 vStart := top;
  835.             end;
  836.         StartTicks := TickCount;
  837.         NextUpdate:=TickCount+10;
  838.         min:=10e99;
  839.         max:=-10e99;
  840.         
  841.         for v := vStart to vStart + nRows - 1 do begin
  842.             base := v * ncols;
  843.             case CurrentMathOp of
  844.                 AddMath: 
  845.                     for h := 0 to nCols - 1 do begin
  846.                             x := s1Data^[base + h] + s2Data^[base + h];
  847.                             x := x * MathGain + MathOffset;
  848.                             rData^[base + h] := x;
  849.                             if x < min then
  850.                                 min := x;
  851.                             if x > max then
  852.                                 max := x;
  853.                         end;
  854.                 SubMath: 
  855.                     for h := 0 to nCols - 1 do begin
  856.                             x := s1Data^[base + h] - s2Data^[base + h];
  857.                             x := x * MathGain + MathOffset;
  858.                             rData^[base + h] := x;
  859.                             if x < min then
  860.                                 min := x;
  861.                             if x > max then
  862.                                 max := x;
  863.                         end;
  864.                 MulMath, cMulMath: 
  865.                     for h := 0 to nCols - 1 do begin
  866.                             x := s1Data^[base + h] * s2Data^[base + h];
  867.                             x := x * MathGain + MathOffset;
  868.                             rData^[base + h] := x;
  869.                             if x < min then
  870.                                 min := x;
  871.                             if x > max then
  872.                                 max := x;
  873.                         end;
  874.                 DivMath: 
  875.                     for h := 0 to nCols - 1 do begin
  876.                             x := s1Data^[base + h] / s2Data^[base + h];
  877.                             x := x * MathGain + MathOffset;
  878.                             rData^[base + h] := x;
  879.                             if x < min then
  880.                                 min := x;
  881.                             if x > max then
  882.                                 max := x;
  883.                         end;
  884.                 MaxMath: 
  885.                     for h := 0 to nCols - 1 do begin
  886.                             x1 := s1Data^[base + h];
  887.                             x2 := s2Data^[base + h];
  888.                             if x1 >= x2 then
  889.                                 x := x1
  890.                             else
  891.                                 x := x2;
  892.                             x := x * MathGain + MathOffset;
  893.                             rData^[base + h] := x;
  894.                             if x < min then
  895.                                 min := x;
  896.                             if x > max then
  897.                                 max := x;
  898.                         end;
  899.                 MinMath: 
  900.                     for h := 0 to nCols - 1 do begin
  901.                             x1 := s1Data^[base + h];
  902.                             x2 := s2Data^[base + h];
  903.                             if x1 <= x2 then
  904.                                 x := x1
  905.                             else
  906.                                 x := x2;
  907.                             x := x * MathGain + MathOffset;
  908.                             rData^[base + h] := x;
  909.                             if x < min then
  910.                                 min := x;
  911.                             if x > max then
  912.                                 max := x;
  913.                         end;
  914.                 CopyMath: 
  915.                     for h := 0 to nCols - 1 do begin
  916.                             x := s1Data^[base + h];
  917.                             x := x * MathGain + MathOffset;
  918.                             rData^[base + h] := x;
  919.                             if x < min then
  920.                                 min := x;
  921.                             if x > max then
  922.                                 max := x;
  923.                         end;
  924.             end; {case}
  925.             if TickCount >= NextUpdate then begin
  926.                 ShowAnimatedWatch;
  927.                 NextUpdate:=TickCount+10;
  928.                 if CommandPeriod then begin
  929.                         beep;
  930.                         AbortMacro;
  931.                         exit(DoRealRealMath)
  932.                     end;
  933.             end;
  934.         end; {for}
  935.         info := dstInfo;
  936.         if isFFT then begin
  937.             DisplayPowerSpectrum(rData);
  938.             SetFFTWindowName(false);
  939.         end else
  940.             DisplayRealImage(rData, min, max, false);
  941.         hunlock(src1Info^.dataH);
  942.         if CurrentMathOp <> copyMath then    
  943.             hunlock(src2Info^.dataH);        
  944.         hunlock(dstInfo^.dataH);        
  945.         ShowTime(StartTicks, roi, '');
  946.     end; {DoRealRealMath}
  947.  
  948.  
  949.  
  950.     procedure DoRealMath (Src1PicNum, Src2PicNum: integer; DstInfo:InfoPtr; roi:rect);
  951.         var
  952.             nrows, ncols, hStart, vStart: LongInt;
  953.             Src1Info, Src2Info: InfoPtr;
  954.             h, v, i: LongInt;
  955.             src1, src2, dst: LineType;
  956.             tmp, tmp1, tmp2, StartTicks: LongInt;
  957.             SaveRow:LongInt;
  958.             NextUpdate: LongInt;
  959.             MaskRect:rect;
  960.             min, max, x, scale, x1, x2: extended;
  961.             BlackIsZero:boolean;
  962.             cvalue1, cvalue2: array[0..255] of extended;
  963.             rData: rImagePtr;
  964.             base: LongInt;
  965.  
  966.     begin
  967.         Src1Info := GetInfoPtr(Src1PicNum);
  968.         Src2Info := GetInfoPtr(Src2PicNum);
  969.         ShowWatch;
  970.         if DstInfo^.DataH = nil then begin
  971.             PutError('Output image must be real.');
  972.             exit(DoRealMath);
  973.         end;
  974.         if (src1Info^.dataH <> nil) or (src2Info^.dataH <> nil) then begin
  975.             doRealRealMath(Src1Info, Src2Info, DstInfo, roi);
  976.             exit(DoRealMath);
  977.         end;
  978.         with DstInfo^ do begin
  979.             if DataH = nil then
  980.                 exit(DoRealMath);
  981.             hlock(DataH);
  982.             rData := rImagePtr(DataH^);
  983.         end;
  984.         BlackIsZero:=((Src1Info^.fit=StraightLine) and (Src1Info^.coefficient[2]<0))
  985.                     or ((Src2Info^.fit=StraightLine) and (Src2Info^.coefficient[2]<0));
  986.         with roi do begin
  987.                 ncols := right - left;
  988.                 nrows := bottom - top;
  989.                 hStart := left;
  990.                 vStart := top;
  991.             end;
  992.         info := Src2Info;
  993.         GenerateValues;
  994.         for i:=0 to 255 do cvalue2[i]:=cvalue[i];
  995.         info := Src1Info;
  996.         GenerateValues;
  997.         for i:=0 to 255 do cvalue1[i]:=cvalue[i];
  998.         StartTicks := TickCount;
  999.         NextUpdate:=TickCount+10;
  1000.         min:=10e99;
  1001.         max:=-10e99;
  1002.         
  1003.         for v := vStart to vStart + nRows - 1 do begin
  1004.             info := Src1Info;
  1005.             GetLine(hStart, v, nCols, src1);
  1006.             Info := Src2Info;
  1007.             GetLine(hStart, v, nCols, src2);
  1008.             base := v * ncols;
  1009.             case CurrentMathOp of
  1010.                 AddMath: 
  1011.                     for h := 0 to nCols - 1 do begin
  1012.                             x := cvalue1[src1[h]] + cvalue2[src2[h]];
  1013.                             x := x * MathGain + MathOffset;
  1014.                             rData^[base + h] := x;
  1015.                             if x < min then
  1016.                                 min := x;
  1017.                             if x > max then
  1018.                                 max := x;
  1019.                         end;
  1020.                 SubMath: 
  1021.                     for h := 0 to nCols - 1 do begin
  1022.                             x := cvalue1[src1[h]] - cvalue2[src2[h]];
  1023.                             x := x * MathGain + MathOffset;
  1024.                             rData^[base + h] := x;
  1025.                             if x < min then
  1026.                                 min := x;
  1027.                             if x > max then
  1028.                                 max := x;
  1029.                         end;
  1030.                 MulMath, cMulMath: 
  1031.                     for h := 0 to nCols - 1 do begin
  1032.                             x := cvalue1[src1[h]] * cvalue2[src2[h]];
  1033.                             x := x * MathGain + MathOffset;
  1034.                             rData^[base + h] := x;
  1035.                             if x < min then
  1036.                                 min := x;
  1037.                             if x > max then
  1038.                                 max := x;
  1039.                         end;
  1040.                 DivMath: 
  1041.                     for h := 0 to nCols - 1 do begin
  1042.                             x := cvalue1[src1[h]] / cvalue2[src2[h]];
  1043.                             x := x * MathGain + MathOffset;
  1044.                             rData^[base + h] := x;
  1045.                             if x < min then
  1046.                                 min := x;
  1047.                             if x > max then
  1048.                                 max := x;
  1049.                         end;
  1050.                 MaxMath: 
  1051.                     for h := 0 to nCols - 1 do begin
  1052.                             x1 := cvalue1[src1[h]];
  1053.                             x2 := cvalue2[src2[h]];
  1054.                             if x1 >= x2 then
  1055.                                 x := x1
  1056.                             else
  1057.                                 x := x2;
  1058.                             x := x * MathGain + MathOffset;
  1059.                             rData^[base + h] := x;
  1060.                             if x < min then
  1061.                                 min := x;
  1062.                             if x > max then
  1063.                                 max := x;
  1064.                         end;
  1065.                 MinMath: 
  1066.                     for h := 0 to nCols - 1 do begin
  1067.                             x1 := cvalue1[src1[h]];
  1068.                             x2 := cvalue2[src2[h]];
  1069.                             if x1 <= x2 then
  1070.                                 x := x1
  1071.                             else
  1072.                                 x := x2;
  1073.                             x := x * MathGain + MathOffset;
  1074.                             rData^[base + h] := x;
  1075.                             if x < min then
  1076.                                 min := x;
  1077.                             if x > max then
  1078.                                 max := x;
  1079.                         end;
  1080.                 CopyMath: 
  1081.                     for h := 0 to nCols - 1 do begin
  1082.                             x := cvalue1[src1[h]];
  1083.                             x := x * MathGain + MathOffset;
  1084.                             rData^[base + h] := x;
  1085.                             if x < min then
  1086.                                 min := x;
  1087.                             if x > max then
  1088.                                 max := x;
  1089.                         end;
  1090.             end; {case}
  1091.             if TickCount >= NextUpdate then begin
  1092.                 ShowAnimatedWatch;
  1093.                 NextUpdate:=TickCount+10;
  1094.                 if CommandPeriod then begin
  1095.                         beep;
  1096.                         AbortMacro;
  1097.                         exit(DoRealMath)
  1098.                     end;
  1099.             end;
  1100.         end; {for}
  1101.         info := dstInfo;
  1102.         DisplayRealImage(rData, min, max, BlackisZero);
  1103.         hunlock(dstInfo^.dataH);        
  1104.         ShowTime(StartTicks, roi, '');
  1105.     end; {DoRealMath}
  1106.  
  1107.  
  1108.  
  1109.     procedure DoMath (Src1PicNum, Src2PicNum: integer; DstInfo:InfoPtr; roi:rect);
  1110.         var
  1111.             nrows, ncols, hStart, vStart: integer;
  1112.             Src1Info, Src2Info: InfoPtr;
  1113.             h, v: integer;
  1114.             src1, src2, dst: LineType;
  1115.             tmp, tmp1, tmp2, StartTicks, scale, ScaledGain: LongInt;
  1116.             rtmp,rtmp2: extended;
  1117.             DoScaling: boolean;
  1118.             SaveRow:integer;
  1119.             NextUpdate: LongInt;
  1120.             MaskRect:rect;
  1121.             IntegerOffset: LongInt;
  1122.     begin
  1123.         if TooWide then
  1124.             exit(DoMath);
  1125.         if RealImageMath and not (CurrentMathOp in [AndMath, OrMath, XorMath]) then begin
  1126.             DoRealMath(Src1PicNum, Src2PicNum, DstInfo, roi);
  1127.             exit(DoMath);
  1128.         end;
  1129.         Src1Info := GetInfoPtr(Src1PicNum);
  1130.         Src2Info := GetInfoPtr(Src2PicNum);
  1131.         ShowWatch;
  1132.         with roi do begin
  1133.                 ncols := right - left;
  1134.                 nrows := bottom - top;
  1135.                 hStart := left;
  1136.                 vStart := top;
  1137.             end;
  1138.         StartTicks := TickCount;
  1139.         scale := 10000;
  1140.         ScaledGain := round(MathGain * scale);
  1141.         IntegerOffset := round(MathOffset);
  1142.         DoScaling := (MathGain <> 1.0) or (MathOffset <> 0.0);
  1143.         SaveRow:=vStart;
  1144.         NextUpdate:=TickCount+6; {Update screen 10 times per second}
  1145.         for v := vStart to vStart + nRows - 1 do begin
  1146.                 info := Src1Info;
  1147.                 GetLine(hStart, v, nCols, src1);
  1148.                 Info := Src2Info;
  1149.                 GetLine(hStart, v, nCols, src2);
  1150.                 case CurrentMathOp of
  1151.                     AddMath: 
  1152.                         for h := 0 to nCols - 1 do begin
  1153.                                 tmp := src1[h] + src2[h];
  1154.                                 tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1155.                                 if tmp > 255 then
  1156.                                     tmp := 255;
  1157.                                 if tmp < 0 then
  1158.                                     tmp := 0;
  1159.                                 dst[h] := tmp;
  1160.                             end;
  1161.                     SubMath: 
  1162.                         for h := 0 to nCols - 1 do begin
  1163.                                 tmp := src1[h] - src2[h];
  1164.                                 tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1165.                                 if tmp > 255 then
  1166.                                     tmp := 255;
  1167.                                 if tmp < 0 then
  1168.                                     tmp := 0;
  1169.                                 dst[h] := tmp;
  1170.                             end;
  1171.                     MulMath, cMulMath: 
  1172.                         for h := 0 to nCols - 1 do begin
  1173.                                 tmp := src1[h];
  1174.                                 tmp := tmp * src2[h];
  1175.                                 tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1176.                                 if tmp > 255 then
  1177.                                     tmp := 255;
  1178.                                 if tmp < 0 then
  1179.                                     tmp := 0;
  1180.                                 dst[h] := tmp;
  1181.                             end;
  1182.                     DivMath: 
  1183.                         for h := 0 to nCols - 1 do begin
  1184.                                 rtmp2:=src2[h];
  1185.                                 rtmp := src1[h] / rtmp2;
  1186.                                 tmp := round(rtmp * MathGain) + IntegerOffset;
  1187.                                 if tmp > 255 then
  1188.                                     tmp := 255;
  1189.                                 if tmp < 0 then
  1190.                                     tmp := 0;
  1191.                                 dst[h] := tmp;
  1192.                             end;
  1193.                     AndMath: 
  1194.                         for h := 0 to nCols - 1 do begin
  1195.                                 tmp := band(src1[h], src2[h]);
  1196.                                 if DoScaling then begin
  1197.                                         tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1198.                                         if tmp > 255 then
  1199.                                             tmp := 255;
  1200.                                         if tmp < 0 then
  1201.                                             tmp := 0;
  1202.                                     end;
  1203.                                 dst[h] := tmp;
  1204.                             end;
  1205.                     OrMath: 
  1206.                         for h := 0 to nCols - 1 do begin
  1207.                                 tmp := bor(src1[h], src2[h]);
  1208.                                 if DoScaling then begin
  1209.                                         tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1210.                                         if tmp > 255 then
  1211.                                             tmp := 255;
  1212.                                         if tmp < 0 then
  1213.                                             tmp := 0;
  1214.                                     end;
  1215.                                 dst[h] := tmp;
  1216.                             end;
  1217.                     XorMath: 
  1218.                         for h := 0 to nCols - 1 do begin
  1219.                                 tmp := bxor(src1[h], src2[h]);
  1220.                                 if DoScaling then begin
  1221.                                         tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1222.                                         if tmp > 255 then
  1223.                                             tmp := 255;
  1224.                                         if tmp < 0 then
  1225.                                             tmp := 0;
  1226.                                     end;
  1227.                                 dst[h] := tmp;
  1228.                             end;
  1229.                     MaxMath: 
  1230.                         for h := 0 to nCols - 1 do begin
  1231.                                 tmp1 := src1[h];
  1232.                                 tmp2 := src2[h];
  1233.                                 if tmp1 >= tmp2 then
  1234.                                     tmp := tmp1
  1235.                                 else
  1236.                                     tmp := tmp2;
  1237.                                 if DoScaling then begin
  1238.                                         tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1239.                                         if tmp > 255 then
  1240.                                             tmp := 255;
  1241.                                         if tmp < 0 then
  1242.                                             tmp := 0;
  1243.                                     end;
  1244.                                 dst[h] := tmp;
  1245.                             end;
  1246.                     MinMath: 
  1247.                         for h := 0 to nCols - 1 do begin
  1248.                                 tmp1 := src1[h];
  1249.                                 tmp2 := src2[h];
  1250.                                 if tmp1 <= tmp2 then
  1251.                                     tmp := tmp1
  1252.                                 else
  1253.                                     tmp := tmp2;
  1254.                                 if DoScaling then begin
  1255.                                         tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1256.                                         if tmp > 255 then
  1257.                                             tmp := 255;
  1258.                                         if tmp < 0 then
  1259.                                             tmp := 0;
  1260.                                     end;
  1261.                                 dst[h] := tmp;
  1262.                             end;
  1263.                     CopyMath: 
  1264.                         for h := 0 to nCols - 1 do begin
  1265.                                 tmp := src1[h];
  1266.                                 if DoScaling then begin
  1267.                                         tmp := (tmp * ScaledGain) div scale + IntegerOffset;
  1268.                                         if tmp > 255 then
  1269.                                             tmp := 255;
  1270.                                         if tmp < 0 then
  1271.                                             tmp := 0;
  1272.                                     end;
  1273.                                 dst[h] := tmp;
  1274.                             end;
  1275.                 end;
  1276.                 Info := DstInfo;
  1277.                 PutLine(0, v - vstart, nCols, Dst);
  1278.                 if TickCount>=NextUpdate then begin
  1279.                     SetRect(MaskRect, hStart, SaveRow, hStart+ncols, v + 1);
  1280.                     UpdateScreen(MaskRect);
  1281.                     SaveRow:=v+1;
  1282.                     NextUpdate:=TickCount+6;
  1283.                     ShowAnimatedWatch;
  1284.                     if CommandPeriod then begin
  1285.                             UpdateScreen(info^.RoiRect);
  1286.                             beep;
  1287.                             AbortMacro;
  1288.                             exit(DoMath)
  1289.                         end;
  1290.                 end;
  1291.             end;
  1292.         with info^ do begin
  1293.                 ShowTime(StartTicks, RoiRect, '');
  1294.                 SetRect(MaskRect, hStart, SaveRow, hStart+ncols, vStart+nRows);
  1295.                 UpdateScreen(MaskRect);
  1296.                 Changes := true;
  1297.                 RemoveDensityCalibration;
  1298.             end;
  1299.     end; {DoMath}
  1300.  
  1301.  
  1302.     function ImageTitle (var PicNumber: integer): str255;
  1303.         var
  1304.             TempInfo: InfoPtr;
  1305.     begin
  1306.         if (PicNumber < 1) or (PicNumber > nPics) then
  1307.             PicNumber := 1;
  1308.         TempInfo := pointer(WindowPeek(PicWindow[PicNumber])^.RefCon);
  1309.         ImageTitle := TempInfo^.title;
  1310.     end;
  1311.  
  1312.  
  1313.     procedure ImageMathUProc (d: DialogPtr; item: integer);
  1314.      {User proc for Image Math dialog box}
  1315.         const
  1316.             ops = '';
  1317.         var
  1318.             str: str255;
  1319.             VersInfo: str255;
  1320.             r: rect;
  1321.     begin
  1322.         SetPort(d);
  1323.         GetDItemRect(d, item, r);
  1324.         DrawDropBox(r);
  1325.         case item of
  1326.             Src1Item: 
  1327.                 DrawPopUpText(ImageTitle(MathSrc1), r);
  1328.             Src2Item: 
  1329.                 DrawPopUpText(ImageTitle(MathSrc2), r);
  1330.             OpItem:  begin
  1331.                     GetMenuItemText(ImageMathOpsMenuH, ord(CurrentMathOp) + 1, str);
  1332.                     DrawPopUpText(str, r);
  1333.                 end;
  1334.         end;
  1335.     end;
  1336.  
  1337.  
  1338.     function PopUpImageList (r: rect; CurrentImage: integer): integer;
  1339.         var
  1340.             i: integer;
  1341.     begin
  1342.         for i := 1 to nPics do begin
  1343.                 AppendMenu(ImageListMenuH, ' ');
  1344.                 SetMenuItemText(ImageListMenuH, i, ImageTitle(i));
  1345.             end;
  1346.         PopUpImageList := PopUpMenu(ImageListMenuH, r.left, r.top, CurrentImage);
  1347.         for i := 1 to nPics do
  1348.             DeleteMenuItem(ImageListMenuH, 1);
  1349.     end;
  1350.  
  1351.  
  1352.     procedure DoImageMath;
  1353.         const
  1354.             ScaleItem = 10;
  1355.             OffSetMenuItemText = 11;
  1356.             ResultItem = 12;
  1357.             RealMathItem=14;
  1358.         var
  1359.             d: DialogPtr;
  1360.             item, i, MenuItem: integer;
  1361.             r: rect;
  1362.             str: str255;
  1363.             ScaleOffEdited: boolean;
  1364.             roi:rect;
  1365.             DstInfo:InfoPtr;
  1366.  
  1367.         procedure ShowScaleAndOffset;
  1368.         begin
  1369.             SetDReal(d, ScaleItem, MathGain, 4);
  1370.             if RealImageMath then
  1371.                 SetDReal(d, OffSetMenuItemText, MathOffset, 2)
  1372.             else
  1373.                 SetDNum(d, OffSetMenuItemText, round(MathOffset));
  1374.         end;
  1375.  
  1376.         procedure ResetScaleOff;
  1377.         begin
  1378.             if not ScaleOffEdited then begin
  1379.                     MathGain := 1.0;
  1380.                     MathOffset := 0.0;
  1381.                     ShowScaleAndOffset;
  1382.                 end;
  1383.         end;
  1384.  
  1385.         procedure CheckForRealImage(picNum: integer);
  1386.         var
  1387.             srcInfo:InfoPtr;
  1388.         begin
  1389.             srcInfo := GetInfoPtr(picNum);
  1390.             if srcInfo^.dataH <> nil then begin
  1391.                 RealImageMath := true;
  1392.                 SetDlogItem(d, RealMathItem, ord(RealImageMath));
  1393.             end;
  1394.         end;
  1395.     
  1396.     begin
  1397.         if ImageMathUserProc=nil
  1398.             then ImageMathUserProc:=NewRoutineDescriptor(@ImageMathUProc, uppUserItemProcInfo, GetCurrentISA);
  1399.         InitCursor;
  1400.         ScaleOffEdited := false;
  1401.         d := GetNewDialog(200, nil, pointer(-1));
  1402.         SetUProc(d, Src1Item, handle(ImageMathUserProc));
  1403.         SetUProc(d, Src2Item, handle(ImageMathUserProc));
  1404.         SetUProc(d, OpItem, handle(ImageMathUserProc));
  1405.         ShowScaleAndOffset;
  1406.         SetDString(d, ResultItem, MathResult);
  1407.         SetDlogItem(d, RealMathItem, ord(RealImageMath));
  1408.         if (MathSrc1 = 1) and (MathSrc2 = 1) then
  1409.             MathSrc1 := info^.PicNum;
  1410.         if MathSrc1 = MathSrc2 then begin
  1411.                 if MathSrc1 = info^.PicNum then begin
  1412.                         MathSrc2 := MathSrc2 + 1;
  1413.                         if MathSrc2 > nPics then
  1414.                             MathSrc2 := 1;
  1415.                     end
  1416.                 else
  1417.                     MathSrc2 := info^.PicNum;
  1418.             end;
  1419.         CheckForRealImage(MathSrc1);
  1420.         CheckForRealImage(MathSrc2);
  1421.         repeat
  1422.             ModalDialog(nil, item);
  1423.             if item = Src1Item then begin
  1424.                     setport(d);
  1425.                     GetDItemRect(d, item, r);
  1426.                     MenuItem := PopUpImageList(r, MathSrc1);
  1427.                     if MenuItem <> 0 then
  1428.                         MathSrc1 := MenuItem;
  1429.                     CheckForRealImage(MathSrc1);
  1430.                     InvalRect(r);
  1431.                 end;
  1432.             if item = Src2Item then begin
  1433.                     setport(d);
  1434.                     GetDItemRect(d, item, r);
  1435.                     MenuItem := PopUpImageList(r, MathSrc2);
  1436.                     if MenuItem <> 0 then
  1437.                         MathSrc2 := MenuItem;
  1438.                     CheckForRealImage(MathSrc2);
  1439.                     InvalRect(r);
  1440.                 end;
  1441.             if item = OpItem then begin
  1442.                     setport(d);
  1443.                     GetDItemRect(d, item, r);
  1444.                     MenuItem := PopUpMenu(ImageMathOpsMenuH, r.left, r.top, ord(CurrentMathOp) + 1);
  1445.                     case MenuItem of
  1446.                         1:  begin
  1447.                                 CurrentMathOp := AddMath;
  1448.                                 if not ScaleOffEdited then begin
  1449.                                         if RealImageMath then
  1450.                                             ResetScaleOff
  1451.                                         else begin
  1452.                                             MathGain := 0.5;
  1453.                                             MathOffset := 0.0;
  1454.                                             ShowScaleAndOffset;
  1455.                                         end;
  1456.                                     end;
  1457.                             end;
  1458.                         2:  begin
  1459.                                 CurrentMathOp := SubMath;
  1460.                                 if not ScaleOffEdited then begin
  1461.                                         if RealImageMath then
  1462.                                             ResetScaleOff
  1463.                                         else begin
  1464.                                             MathGain := MathSubGain;
  1465.                                             MathOffset := MathSubOffset;
  1466.                                             ShowScaleAndOffset;
  1467.                                         end;
  1468.                                     end;
  1469.                             end;
  1470.                         3:  begin
  1471.                                 CurrentMathOp := MulMath;
  1472.                                 if not ScaleOffEdited then begin
  1473.                                         if RealImageMath then
  1474.                                             ResetScaleOff
  1475.                                         else begin
  1476.                                             MathGain := 1.0 / 255.0;
  1477.                                             MathOffset := 0.0;
  1478.                                             ShowScaleAndOffset;
  1479.                                         end;
  1480.                                     end;
  1481.                             end;
  1482.                         4:  begin
  1483.                                 CurrentMathOp := DivMath;
  1484.                                 if not ScaleOffEdited then begin
  1485.                                         if RealImageMath then
  1486.                                             ResetScaleOff
  1487.                                         else begin
  1488.                                             MathGain := 255.0;
  1489.                                             MathOffset := 0.0;
  1490.                                             ShowScaleAndOffset;
  1491.                                         end;
  1492.                                     end;
  1493.                             end;
  1494.                         5:  begin
  1495.                                 CurrentMathOp := AndMath;
  1496.                                 ResetScaleOff;
  1497.                             end;
  1498.                         6:  begin
  1499.                                 CurrentMathOp := OrMath;
  1500.                                 ResetScaleOff;
  1501.                             end;
  1502.                         7:  begin
  1503.                                 CurrentMathOp := XorMath;
  1504.                                 ResetScaleOff;
  1505.                             end;
  1506.                         8:  begin
  1507.                                 CurrentMathOp := MaxMath;
  1508.                                 ResetScaleOff;
  1509.                             end;
  1510.                         9:  begin
  1511.                                 CurrentMathOp := MinMath;
  1512.                                 ResetScaleOff;
  1513.                             end;
  1514.                         10:    begin
  1515.                                 CurrentMathOp := cMulMath;
  1516.                                 ResetScaleOff;
  1517.                             end;
  1518.                         11:    begin
  1519.                                 CurrentMathOp := CopyMath;
  1520.                                 ResetScaleOff;
  1521.                             end;
  1522.                         otherwise
  1523.                     end;
  1524.                     InvalRect(r);
  1525.                 end;
  1526.             if item = ScaleItem then begin
  1527.                     MathGain := GetDReal(d, ScaleItem);
  1528.                     ScaleOffEdited := true;
  1529.                 end;
  1530.             if item = OffSetMenuItemText then begin
  1531.                     MathOffset := GetDReal(d, OffSetMenuItemText);
  1532.                     ScaleOffEdited := true;
  1533.                 end;
  1534.             if item = RealMathItem then begin
  1535.                     RealImageMath := not RealImageMath;
  1536.                     SetDlogItem(d, RealMathItem, ord(RealImageMath));
  1537.                     ResetScaleOff;
  1538.                 end;
  1539.         until (item = ok) or (item = cancel);
  1540.         MathResult := GetDString(d, ResultItem);
  1541.         DisposeDialog(d);
  1542.         if item = cancel then
  1543.             exit(DoImageMath);
  1544.         if not GetMathRoi(MathSrc1, MathSrc2, roi) then
  1545.             exit(DoImageMath);
  1546.         with roi do
  1547.             if RealImageMath then begin
  1548.                 if not NewRealWindow(MathResult, right-left, bottom-top) then
  1549.                     exit(DoImageMath)
  1550.             end else begin
  1551.                 if not NewPicWindow(MathResult, right-left, bottom-top) then
  1552.                     exit(DoImageMath)
  1553.             end;
  1554.         DstInfo := Info;
  1555.         DoMath(MathSrc1, MathSrc2, DstInfo, roi);
  1556.         if CurrentMathOp=SubMath then begin
  1557.             MathSubGain:=MathGain;
  1558.             MathSubOffset:=MathOffset;
  1559.         end;
  1560.     end;
  1561.  
  1562.  
  1563.  
  1564. end.